package com.pi.uc.service;

import java.text.MessageFormat;
import java.util.List;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import com.pi.uc.model.user.UserRegisterPostForm;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.pi.base.contants.WxConstants;
import com.pi.base.dto.result.respcode.error.ErrorServer;
import com.pi.base.dto.result.respcode.user.UcResp;
import com.pi.base.enumerate.file.FileSource;
import com.pi.base.enumerate.record.RecordState;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.enumerate.user.Gender;
import com.pi.base.exception.ServiceException;
import com.pi.base.util.bean.ObjectTool;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.http.v2.HttpPostUtil;
import com.pi.comm.sequence.SnowflakeFactory;
import com.pi.comm.validate.SpringValidateUtil;
import com.pi.config.model.PartnerAppConfig;
import com.pi.config.service.ConfigService;
import com.pi.uc.dao.entity.UcUserEntity;
import com.pi.uc.dao.entity.UcUserExtEntity;
import com.pi.uc.dao.entity.UcUserWxEntity;
import com.pi.uc.dao.mapper.UcUserExtMapper;
import com.pi.uc.dao.mapper.UcUserMapper;
import com.pi.uc.dao.param.UcUserExtParam;
import com.pi.uc.dao.param.UcUserParam;
import com.pi.uc.model.user.UserExtendPostForm;
import com.pi.uc.model.user.UserPostForm;
import com.pi.uc.model.userlogin.UserLoginPostForm;
import com.pi.uc.model.wx.mini.WxFullUserInfo;
import com.pi.uc.model.wx.mini.WxMiniAuthInfo;
import com.pi.uc.model.wx.mini.WxMiniUserInfo;
import com.pi.uc.service.validate.group.UserAdd;
import com.pi.uc.service.validate.group.UserAddWithExt;
import com.pi.uc.service.validate.group.UserUpdateWithExt;
import com.pi.uc.util.TokenUtil;
import com.pi.uc.vo.UserExtendInfoVo;
import com.pi.uc.vo.UserWechatBindVo;

@Validated
@Service
public class UcUserService {
    private static final Logger logger = LoggerFactory.getLogger(UcUserService.class);
    @Autowired
    private ConfigService configService;
    @Autowired
    private UcUserWxService userWxService;
    @Autowired
    private UcUserMapper userMapper;
    @Autowired
    private UserPicService userPicService;
    @Autowired
    private UcUserExtMapper userExtMapper;

    public String getTokenByUserId(Long userId) throws Exception {
        UcUserEntity entity = queryUserInfo(userId);
        return TokenUtil.getUserToken(entity);
    }

    private String getTokenByUserInfo(UcUserEntity entity) throws Exception {
        return TokenUtil.getUserToken(entity);
    }

    public String bindWeChat(@Valid UserLoginPostForm userInfo) throws Exception {
        //获取用户信息
        UcUserEntity entity = bindWeChatUser(userInfo);
        //保存登录会话
        String token = getTokenByUserInfo(entity);
        return token;
    }

    public UserWechatBindVo bindWeChatVo(@Valid UserLoginPostForm userInfo) throws Exception {
        //获取用户信息
        UcUserEntity entity = bindWeChatUser(userInfo);
        //保存登录会话
        String token = getTokenByUserInfo(entity);
        UserWechatBindVo vo = new UserWechatBindVo();
        vo.setFirstBind(StringUtils.isBlank(entity.getMobile()));
        vo.setRefreshUserInfo(vo.isFirstBind());
        vo.setUserId(entity.getId());
        vo.setToken(token);
        return vo;
    }

    private UcUserEntity bindWeChatUser(@Valid UserLoginPostForm userInfo) throws Exception {
        //查询app配置
        PartnerAppConfig config = configService.queryPartnerAppConfig(userInfo.getSourceId());
        //校验授权
        WxMiniAuthInfo wxUserInfo = validWxAuthorization(userInfo.getWxCode(), config);
        //获取用户信息
        UcUserEntity entity = createIfNotExistUser(wxUserInfo, userInfo);
        return entity;
    }

    public String updateUserAvatar(MultipartFile file,
                                   @NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId) throws Exception {
        //查询用户信息
        UcUserEntity entity = queryUserInfo(userId);
        String url = userPicService.transferAvatarToLocal(file, FileSource.USER_PIC, entity.getSourceId(), entity.getId());
        //更新用户信息
        entity.setAvatar(url);
        userMapper.updateById(entity);
        return url;
    }

    public String uploadUserPic(MultipartFile file, FileSource fileSource,
                                @NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId) throws Exception {
        //查询用户信息
        UcUserEntity entity = queryUserInfo(userId);
        String url = userPicService.transferAvatarToLocal(file, fileSource, entity.getSourceId(), entity.getId());
        //保存用户图片数据到表(待补齐)
        return url;
    }

    public void updateUserInfo(UserPostForm form) {
        SpringValidateUtil.validate(form, UserAdd.class);
        UcUserEntity entity = queryUserInfo(form.getLoginUserId());
        //valid校验手机号不为空之后，需要校验是否是手机号更改
        checkMobileChange(form.getMobile(), entity.getMobile(), entity.getSourceId());

        entity.setAge(form.getAge());
        entity.setMobile(form.getMobile());
        entity.setName(form.getName());
        entity.setSex(form.getSex());
        entity.setEducation(form.getEducation());
        int i = userMapper.updateById(entity);
        if (i != 1) {
            throw new ServiceException(
                    ErrorServer.OPERATE_FAILED.getTag(),
                    ErrorServer.OPERATE_FAILED.getErrorCode());
        }
    }

    public Long addUserInfo(UserRegisterPostForm form) {
        SpringValidateUtil.validate(form, UserAdd.class);
        UcUserEntity entity = queryUserInfoByPhoneInternal(form.getMobile(), form.getSourceId());
        if (null == entity) {
            UcUserEntity add = new UcUserEntity();
            add.setAge(form.getAge());
            add.setName(form.getName());
            add.setSex(form.getSex());
            add.setMobile(form.getMobile());
            add.setEducation(form.getEducation());
            add.setSourceId(form.getSourceId());
            add.setId(SnowflakeFactory.getDefaultWorker().nextId());
            add.setPassword(StringUtils.EMPTY);
            add.setAvatar(StringUtils.EMPTY);
            add.setEmail(StringUtils.EMPTY);
            add.setNickName(form.getName());
            add.setState(RecordState.STATE_NORMAL.getCode());
            userMapper.insert(add);
            return add.getId();
        } else {
            //valid校验手机号不为空之后，需要校验是否是手机号更改
            checkMobileChange(form.getMobile(), entity.getMobile(), entity.getSourceId());
            UcUserEntity update = new UcUserEntity();
            update.setNickName(form.getNickName());
            update.setAge(form.getAge());
            update.setMobile(form.getMobile());
            update.setName(form.getName());
            update.setSex(form.getSex());
            update.setEducation(form.getEducation());
            update.setNickName(form.getName());
            update.setState(RecordState.STATE_NORMAL.getCode());
            update.setId(entity.getId());
            userMapper.updateById(entity);
            return update.getId();
        }
    }


    /**
     * @param form
     * @description 微信绑定后首次添加
     */
    public void addUserInfoWithExtend(UserExtendPostForm form) {
        SpringValidateUtil.validate(form, UserAddWithExt.class);
        updateUserInfoWithExtendDirect(form);
    }

    /**
     * @param userFullInfo
     * @description 微信绑定后首次添加
     */
    public void addUserInfoWithExtendByWeChat(
            WxFullUserInfo userFullInfo,
            @NotNull(message = "UC_USER.USER_ID_EMPTY") long userId) {
        WxFullUserInfo wxUserInfo = decryptWxInfo(userFullInfo);
        WxMiniUserInfo userInfo = wxUserInfo.getUserInfo();
        UserExtendPostForm form = new UserExtendPostForm();
        form.setAge(0);
        form.setEducation(StringUtils.EMPTY);
        form.setLoginUserId(userId);
        form.setMobile(StringUtils.EMPTY);
        form.setName(StringUtils.EMPTY);
        form.setSex(Gender.getGender(userInfo.getGender()).getCode());
        form.setWeight(0);
        form.setNickName(wxUserInfo.getUserInfo().getNickName());
        form.setAvatar(wxUserInfo.getUserInfo().getAvatarUrl());
        updateUserInfoWithExtendDirect(form);
    }

    public void updateUserInfoWithExtend(UserExtendPostForm form) {
        SpringValidateUtil.validate(form, UserUpdateWithExt.class);
        updateUserInfoWithExtendDirect(form);
    }

    /**
     * 修改用户手机号
     *
     * @param userId
     * @param mobile
     * @author zoumy
     */
    public void updateUserMobileWithExtend(@NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId,
                                           @NotNull(message = "UC_USER.MOBILE_IS_EMPTY")
                                           @Length(min = 11, max = 11, message = "UC_USER.MOBILE_LENGTH_ERROR") String mobile) {
        // 查询当前登录用户对象
        UcUserEntity entity = queryUserInfo(userId);
        // 原先已经有手机号并且从未修改 直接返回
        if (mobile.equals(entity.getMobile())) {
            return;
        }
        //校验是否是手机号重复
        //checkMobileChange(mobile, entity.getMobile(), entity.getSourceId());
        UcUserEntity phoneOccupiedUser = queryUserInfoByPhone(mobile, entity.getSourceId());
        if (null != phoneOccupiedUser) {
            throw new ServiceException(
                    UcResp.RESP_USER_MOBILE_DUMPLICATE.getTag(),
                    UcResp.RESP_USER_MOBILE_DUMPLICATE.getErrorCode());
        }
        // 更新
        entity.setMobile(mobile);
        int i = userMapper.updateById(entity);
        if (i != 1) {
            throw new ServiceException(
                    ErrorServer.OPERATE_FAILED.getTag(),
                    ErrorServer.OPERATE_FAILED.getErrorCode());
        }

    }


    private void updateUserInfoWithExtendDirect(UserExtendPostForm form) {
        UcUserEntity entity = queryUserInfo(form.getLoginUserId());
        //valid校验手机号不为空之后，需要校验是否是手机号更改
        checkMobileChange(form.getMobile(), entity.getMobile(), entity.getSourceId());
        entity.setNickName(StringUtils.isBlank(form.getNickName()) ? StringUtils.EMPTY : form.getNickName());
        entity.setAvatar(StringUtils.isBlank(form.getAvatar()) ? StringUtils.EMPTY : form.getAvatar());
        entity.setAge(form.getAge());
        entity.setMobile(form.getMobile());
        entity.setName(form.getName());
        entity.setSex(form.getSex());
        entity.setEducation(form.getEducation());
        int i = userMapper.updateById(entity);
        if (i != 1) {
            throw new ServiceException(
                    ErrorServer.OPERATE_FAILED.getTag(),
                    ErrorServer.OPERATE_FAILED.getErrorCode());
        }
        if (null != form.getWeight()) {
            UcUserExtEntity extEntity = new UcUserExtEntity();
            extEntity.setUserId(entity.getId());
            extEntity.setState(RecordState.STATE_NORMAL.getCode());
            extEntity.setWeight(form.getWeight());
            createOrUpdateUserExt(extEntity);
        }
    }

    public List<UcUserEntity> queryUserByIds(List<Long> ids) {
        if (null == ids || ids.isEmpty()) {
            return null;
        }
        return userMapper.getByIds(ids);
    }

    public UcUserEntity queryUserInfo(@NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId) {
        UcUserEntity entity = queryUserInfoIfExists(userId);
        if (null == entity) {
            throw new ServiceException(
                    UcResp.RESP_USER_NOT_FOUND.getTag(),
                    UcResp.RESP_USER_NOT_FOUND.getErrorCode());
        }
        return entity;
    }

    public UserExtendInfoVo queryUserFullInfo(@NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId) {
        UcUserEntity entity = queryUserInfoIfExists(userId);
        if (null == entity) {
            throw new ServiceException(
                    UcResp.RESP_USER_NOT_FOUND.getTag(),
                    UcResp.RESP_USER_NOT_FOUND.getErrorCode());
        }
        UserExtendInfoVo fullInfo = new UserExtendInfoVo();
        BeanUtils.copyProperties(entity, fullInfo);
        UcUserExtEntity userExtEntity = getUserExtIfExist(userId);
        fullInfo.setUserId(userId.toString());
        fullInfo.setWeight(null != userExtEntity ? userExtEntity.getWeight() : 0);
        return fullInfo;
    }

    public UcUserEntity queryUserInfoIfExists(@NotNull(message = "UC_USER.USER_ID_EMPTY") Long userId) {
        UcUserEntity entity = userMapper.findOne(userId);
        return entity;
    }

    public UcUserEntity queryUserInfoByPhone(
            @NotNull(message = "UC_USER.MOBILE_IS_EMPTY")
            @Length(min = 11, max = 11, message = "UC_USER.MOBILE_LENGTH_ERROR") String phone,
            @NotNull(message = "UC_USER.SOURCE_ID_EMPTY") Long sourceId) {
        return queryUserInfoByPhoneInternal(phone, sourceId);
    }

    private UcUserEntity queryUserInfoByPhoneInternal(String phone, Long sourceId) {
        UcUserParam param = new UcUserParam();
        param.setMobile(phone);
        param.setSourceId(sourceId);
        param.setState(RecordState.STATE_NORMAL.getCode());
        List<UcUserEntity> userList = userMapper.findList(param);
        return ObjectTool.getOne(userList);
    }

    public UcUserEntity queryUserInfoByWxInfo(
            Long sourceId, String wxOpenId, String wxUnionId) {
        UcUserWxEntity wxEntity =
                userWxService.queryWxInfoIfExist(sourceId, wxOpenId, wxUnionId);
        if (null != wxEntity) {
            return userMapper.findOne(wxEntity.getUserId());
        }
        return null;
    }

    private UcUserEntity createIfNotExistUser(WxMiniAuthInfo wxUserInfo, UserLoginPostForm user) {
        UcUserEntity entity = queryUserInfoByWxInfo(
                user.getSourceId(), wxUserInfo.getOpenid(), wxUserInfo.getUinionid());
        if (null != entity) {
            if ((user.getGender() != entity.getSex()
                    && user.getGender() > 0 && user.getGender() < 3)) {
                entity.setSex(user.getGender());
            }
            if (StringUtils.isNotBlank(user.getAvatarUrl())
                    && entity.getAvatar().equals(user.getAvatarUrl())) {
                entity.setAvatar(user.getAvatarUrl());
            }
            entity.setState(RecordState.STATE_NORMAL.getCode());
            userMapper.updateById(entity);
        } else {
            entity = translateWxUserInfoToEntity(wxUserInfo, user);
            entity.setSourceId(user.getSourceId());
            entity.setState(RecordState.STATE_NORMAL.getCode());
            entity.setEmail(StringUtils.EMPTY);
            entity.setId(SnowflakeFactory.getDefaultWorker().nextId());
            logger.info("获取到了用户id: {}", entity.getId());
            userMapper.insert(entity);
        }

        userWxService.addUserWxInfoIfNotExist(
                wxUserInfo.getOpenid(), wxUserInfo.getUinionid(),
                entity.getId(), user.getSourceId());
        return entity;
    }

    private UcUserEntity translateWxUserInfoToEntity(WxMiniAuthInfo wxUserInfo, UserLoginPostForm user) {
        UcUserEntity entity = new UcUserEntity();
        entity.setAge(0);
        entity.setSex((user.getGender() > 0 && user.getGender() < 3) ?
                user.getGender() : 1);
        entity.setMobile("");
        entity.setName("");
        entity.setNickName(null != user.getNickName() ? user.getNickName() : "");
        entity.setPassword("");
        entity.setState(RecordState.STATE_NORMAL.getCode());
        entity.setAvatar(null != user.getAvatarUrl() ? user.getAvatarUrl() : "");
        entity.setEducation("");
        return entity;
    }

    private WxMiniAuthInfo validWxAuthorization(String wxCode, PartnerAppConfig config)
            throws Exception {
        WxMiniAuthInfo baseInfo = HttpPostUtil.getRestResult(
                MessageFormat.format(
                        WxConstants.WCHAT_MINI_OPENID_PATTERN,
                        config.getAppId(),
                        config.getAppSecret(),
                        wxCode),
                null, WxMiniAuthInfo.class);
        checkWeChatAuth(baseInfo, new Object[]{config.getAppId(), config.getAppSecret(), wxCode}, wxCode);

//  设备缓存, 默认1天
        RedisUtil.directset(
                RedisCacheEnum.USER_WX_INFO,
                JSON.toJSONString(baseInfo), WxConstants.DEFAULT_WECHAT_TOKEN_EXPIRED,
                new Object[]{baseInfo.getOpenid()});
        return baseInfo;
    }


    private void checkWeChatAuth(WxMiniAuthInfo userInfo, Object[] param, String wxCode) {
        if (null == userInfo
                || (null != userInfo.getErrcode() && userInfo.getErrcode() > 0)) {
            logger.error("获取用户授权失败, 请求参数为: {}, 授权码:{}", MessageFormat.format(
                    WxConstants.WCHAT_OPENID_PATTERN, param), wxCode);
            throw new ServiceException("USERACTION.WECHAT_AUTH_FAILED");
        }
    }

    private void checkMobileChange(String updated, String origin, Long sourceId) {
        if (StringUtils.isNotBlank(updated) && !updated.equals(origin)) {
//    如果用户修改了手机号码, 需要验证手机号码是否已绑定
            UcUserEntity phoneOccupiedUser = queryUserInfoByPhone(updated, sourceId);
            if (null != phoneOccupiedUser) {
                throw new ServiceException(
                        UcResp.RESP_USER_MOBILE_DUMPLICATE.getTag(),
                        UcResp.RESP_USER_MOBILE_DUMPLICATE.getErrorCode());
            }
        }
    }

    private WxFullUserInfo decryptWxInfo(
            @Valid @NotNull(message = "UC_USER.USER_WXINFO_LOST")
                    WxFullUserInfo userFullInfo) {
        return userFullInfo;
    }

    private void createOrUpdateUserExt(UcUserExtEntity entity) {
        UcUserExtEntity userExtEntity = getUserExtIfExist(entity.getUserId());
        if (null == userExtEntity) {
            userExtMapper.insert(entity);
        } else {
            userExtEntity.setWeight(entity.getWeight());
            userExtMapper.updateById(userExtEntity);
        }
    }

    private UcUserExtEntity getUserExtIfExist(Long userId) {
        UcUserExtParam param = new UcUserExtParam();
        param.setUserId(userId);
        return ObjectTool.getOne(userExtMapper.findList(param));

    }
}
